Control Tower管理外リージョンにガードレールを展開して全リージョン保護してみた
こんにちは、臼田です。
みなさん、AWS環境の統制管理してますか?(挨拶
今回は先日公開された以下のAWSブログに基づいて、Control Tower管理外リージョンへガードレールを展開してみました。
背景
Control Towerとは
Control TowerはAWSアカウントを複数束ねて統制管理する仕組みです。
元々AWSの多数の利用実績より生まれたマルチアカウント管理の手法であるLanding Zoneという考え方があり、それに基づいた一つの実装方式としてAWS Landing Zoneソリューションが生まれました。
Control TowerはAWS Landing Zoneソリューションを更にマネージドサービスとして提供するもので、マルチアカウントの管理を行うためにLanding Zoneを簡単に構築して、継続して維持管理できガバナンスを利かせることが可能になります。
Landing Zone自体は考え方なので実装はControl Towerを使わなくても可能ですが、Control Towerの展開する形がハマる場合には、Control Towerを使うことにより展開が簡単であったり、ある程度の管理を任せることが可能です。
以下のような環境の展開が可能です。
詳細を知りたい場合には以下も合わせてご確認ください。
Control Towerの(現状の)欠点
AWSのサービスの殆どはコンプライアンス要件を満たしやすいようにリージョン毎明確に分けて管理できます。一方で、各リージョンで対応しているサービスに違いがあることもあり、現状(2020/11/05)ではControl Towerも対応していないリージョンがあります。
現状のControl Towerの場合、対応しているリージョンを列挙したほうが早いです。以下の5つのリージョンのみです。
- 米国東部 (バージニア北部)us-east-1
- 米国東部 (オハイオ)us-east-2
- 米国西部 (オレゴン)us-west-2
- アジアパシフィック (シドニー)ap-southeast-2
- 欧州 (アイルランド)eu-west-1
残念ながら東京にも来ていません。
Control Towerの機能としてはマルチアカウントの管理統制であるため、アカウント自体を管理することにリージョンの制限はあまり影響しません。実態としてはAWS Organizationsと連携してアカウントを管理し、SCPを活用して予防的ガードレールを展開し、AWSアカウントへの認証情報はAWS SSOで管理します。
しかし、AWS Config Rulesを利用して展開する発見的(検出)ガードレールは違います。AWS Configはリージョナルサービスであり、Control Tower管理外のリージョンでガードレールを適用できません。
もう少しガードレールについて説明すると、Control Towerには先述の2種類のガードレールが存在します。
Organizations内のSCP(サービスコントロールポリシー)を利用したガードレールは、AWSアカウント自体にどのようなAPIを禁止するか、などのポリシーをPolicyドキュメントの形式でリージョン関係なく適用できます。これは危ない操作をさせない(実行できない)性質のため予防的ガードレールと呼ばれます。
AWS Config Rulesを利用したガードレールは、AWSの各リソースの設定値の変更管理を行うConfigの機能の一つであるConfig Rulesにより危ない設定を検知する、発見的(検出)ガードレールと呼ばれます。こちらはAWS Config自体がリージョナルサービスであるためそもそもConfig自体を各リージョンで有効化していく必要があり、現状のControl Towerでは直接操作できません。
つまり、Control Towerのガードレールのうち、発見的(検出)ガードレールだけは管理外リージョンに適用できない状況です。
Conformance Packsによる管理外リージョンのガードレール適用
そこで、今回紹介するソリューションの出番です。
Conformance PacksはConfigの機能の一つで、Config Rulesを一括で展開する仕組みです。Conformance PacksはOrganizationsと連携して、管理しているAWSアカウント全体にConfig Rulesを展開することが可能です。
そして、Conformance PacksではControl Towerで展開するConfig Rulesと同じ内容のサンプルテンプレートが用意されているため、これを使うことでControl Tower管理外のリージョンのガードレールも自動で展開されるようにします。
設定したガードレールは共通してAuditアカウントのConfigアグリゲーターに集約することが可能なので、ガードレールの遵守状況は一括で管理できます。
このソリューションはControl Towerのアップデートにも対応していて、Control Towerが新しいリージョンに対応した場合の手順が用意されています。安心して展開できますね。
注意事項
メリットもありますがちょっとしたデメリットもあります。
Control TowerとConformance Packsによるガードレール展開は直接連携していないので、ルールの2重管理になります。
持っているルールセットは同じですが、Control Towerで有効化/無効化したものはConformance Packsの方でも同じ用に有効化/無効化する必要があり2箇所で設定変更が必要になります。ただ、このガードレールは一度決めたら頻繁に変えることは無いと思うので、そこまでデメリットにはならないと思います。
ソリューション詳細
このソリューションは大きく以下の3つの仕組みを展開します。
- 既存環境の管理外リージョンへのConfigの展開
- Control Towerのアカウントファクトリーによる新規アカウント作成をトリガーに新規アカウントの管理外リージョンへのConfigの展開を行うライフサイクルイベントトリガーの展開
- Organizationsを利用した管理外リージョンへのConformance Packsの展開
ここからは込み入った説明なのでとりあえずやってみたい人は飛ばしても大丈夫です。多分やった後に読んだほうが理解できます。私もやって見る前はよくわかってなかったです。
上記の展開はConfigの展開とConformance Packsの展開の2つの作業で行います。
最初はConfigの設定を行うCloudFormationで以下の環境を展開します。
既存環境へConfigの展開
既存環境への展開は上記の図の1を使って説明されています。
CloudFormationから既存環境の管理外リージョンへConfigを展開するLambdaが起動されます。このLambdaはAWSControlTowerBP-BASELINE-CONFIG StackSet
というControl Towerが既に展開したStackSetsから必要な情報を収集しつつCUSTOM-CONFIG StackSet
を作成して管理外リージョンにConfigが展開されます。
収集した情報は図にはないですがパラメータストアにも保存します。
ついでにCNFPACK-LOGARCHIVE-CUSTOM-CONFIG StackSet
という新しいStackSetを作り、Log ArchiveアカウントにConformance Packs用のS3バケットも作成できます。
新規環境へConfigを展開する仕組みの展開
上記の図の2で新規環境へConfigを展開する仕組みを展開しています。
Control Towerでは管理上行われる様々な操作がライフサイクルイベントとして通知されます。この内新規アカウント作成のCreateManagedAccount
をトリガーに管理外リージョンにもConfigが展開されるように、イベントを検知するCloudWatch Eventsとそれを受け取るSQS、実際に実行するLambdaが作成されます。
イベントが実際に発生した際の動きは以下の図で解説されています。
Control Towerのアカウントファクトリーから新規アカウント作成をトリガーに実行され、Lambdaからは先程保存したパラメータストアの情報を使いAWSControlTowerBP-BASELINE-CONFIG StackSet
を拡張して新規アカウントの管理外リージョンにConfigを展開します。上記図ではConformance Packsも書かれていますがこの仕組では直接展開されません。
Conformance Packsの展開
2つ目の作業で今回の肝である管理外リージョンへのガードレールの展開はConformance Packsを利用して行います。
これは図では全然説明されていないので参照元の記事では分かりづらいところですが、Conformance PacksにはOrganizationsと連携してマルチアカウントにConfig Rulesを展開する機能があり、これを利用します。
また、展開するConfig Rulesの情報はControl Towerと同じガードレールになるようにテンプレートを手動で調整し、Auditアカウントに委任して実行します。
これは直接Control Towerと連動していません。
やってみた
前置きが長くなりましたがやっていきます。
準備としてはControl Towerは既に展開されていて、展開するガードレールが固まっている状態とします。
マスターアカウントとAuditアカウントにアクセスでき、AWSCLIが利用できる必要があります。CLIは最新にしておきましょう。
もう一度貼りますがこのブログの手順を見ながら実施していきます。
Config展開
まずControl TowerのマスターアカウントにAWSマネジメントコンソールからログインしてControl Towerを展開しているリージョン(ホームリージョン)にしておきます。
手順で説明されているCloudFormationを展開するリンクを開きます。このリンクはリージョン指定していないので先程切り替えたリージョンになっているはずです。右上を確認してControl Towerのホームリージョンであることを確認して進めます。
スタックのパラメータを設定していきます。
- スタックの名前: そのままで
- Deploy To: 既存のみ・新規のみ・両方(Both)が選べますがデフォルトの
Both
のままで - RegionsToDeploy: 展開するリージョンをカンマ区切りで指定します
- 現状(2020/11/06)なら以下11リージョンが適切です
ap-northeast-1,ap-northeast-2,ap-south-1,ap-southeast-1,ca-central-1,eu-central-1,eu-north-1,eu-west-2,eu-west-3,sa-east-1,us-west-1
- NewStackSetName: そのままで
- SetupConformancePackEnv: Conformance Packsで利用するS3バケットを作るかどうか。デフォルトの
Yes
で - SSEAlgorithm: 上記バケットの暗号化方法。個別のKMSを使いたい場合は変えます。私はデフォルトの
AES256
で - KMSMasterKeyID: 上記
SSEAlgorithm
でaws:kms
にしていたらKeyIDを入れます。AES256
の場合は空欄で - LogArchiveAccountId: Log ArchiveアカウントのアカウントIDで
あとはそのまま進めていき、最後にIAM作成のチェックを入れてスタックの作成を実行します。
しばらくすると展開が完了します。このスタックから更にスタックセットを展開するため時間がかかります。私の環境では15分程度でした。これは対象のリージョンの数によっても変わると思います。もしここで失敗した場合は、エラーメッセージにあるCloudWatch Logsからエラーの内容をたどれる場合がありますが、時間が間に合わずタイムアウトしている場合もあります。その場合やり直したり最初のリージョンを減らすことによりうまくいくことがあります。(一回ハマったのでサポートに修正依頼します)
スタックセットを見に行くと先程パラメータにデフォルトで入っていたCUSTOM-CONFIG-STACKSET
という名前のスタックセットのインスタンスが子アカウントの指定したリージョン(管理外リージョン)に展開されていることが確認できます。
またCNFPACK-LOGARCHIVE-CUSTOM-CONFIG-STACKSET
という名前のスタックセットも作成され、こちらはパラメータで指定していたLog Archiveアカウントのホームリージョンに対してのみインスタンスが作成されます。中身はこの後作るConformance Packsで利用するS3バケットとそのポリシーが作られています。
展開が完了したのでAuditアカウントのアグリゲーターに集約できているかを確認します。AWSCLIにてAuditアカウントで以下のコマンドを実行します。ホームリージョンを--regions
オプションで指定し、対象の管理外リージョンの数だけAwsRegion==`us-west-1`
の部分を追記して実行します。ホームリージョンがus-east-1
で上述した11リージョンが対象なら以下コマンドをそのまま利用できます。
aws configservice describe-configuration-aggregator-sources-status --configuration-aggregator-name aws-controltower-GuardrailsComplianceAggregator --region us-east-1 --query 'AggregatedSourceStatusList[?AwsRegion==`us-west-1` || AwsRegion==`ap-northeast-1` || AwsRegion==`ap-northeast-2` || AwsRegion==`ap-south-1` || AwsRegion==`ap-southeast-1` || AwsRegion==`ca-central-1` || AwsRegion==`eu-central-1` || AwsRegion==`eu-north-1` || AwsRegion==`eu-west-2` || AwsRegion==`eu-west-3` || AwsRegion==`sa-east-1`].{SID:SourceId,Region:AwsRegion,Status:LastUpdateStatus,MSG:LastErrorMessage}' --output table
出力は以下のように出てきます。全てSUCCEEDED
ならOKです。
--------------------------------------------------------- | DescribeConfigurationAggregatorSourcesStatus | +------+------------------+----------------+------------+ | MSG | Region | SID | Status | +------+------------------+----------------+------------+ | None| ap-northeast-1 | 999999999999 | SUCCEEDED | | None| ap-northeast-1 | 888888888888 | SUCCEEDED | | None| eu-west-3 | 777777777777 | SUCCEEDED | | None| eu-north-1 | 777777777777 | SUCCEEDED | …省略…
これで前半のConfig展開作業が完了しました。
Conformance Packs展開
後半はガードレールのルールセットであるConformance Packsの展開です。ここからはAWSCLIで設定していきます。
実はConformance Packsのマルチアカウント展開は現状(2020/11/06)AWSCLIからしかできません。だからAWSCLIを利用する必要があったんですね。
まずマスターアカウントからAuditアカウントにマルチアカウントのConformance Packs展開をできる権限を委任していきます。
マスターアカウントのAWSCLIで以下を実行しOrganizationsと連携したConformance Packsのマルチアカウント展開機能を有効化します。
aws organizations enable-aws-service-access --service-principal=config-multiaccountsetup.amazonaws.com
これは正常に処理されると出力はありません。有効化されたことを以下コマンドで確認します。
aws organizations list-aws-service-access-for-organization
以下のようにconfig-multiaccountsetup.amazonaws.com
が含まれていればOKです。
"EnabledServicePrincipals": [ { "ServicePrincipal": "config-multiaccountsetup.amazonaws.com", "DateEnabled": "2020-11-06T13:43:53.627000+09:00"
続いて委任するコマンドです。最後の--account-id
にはAuditのアカウントIDを入力します。
aws organizations register-delegated-administrator --service-principal=config-multiaccountsetup.amazonaws.com --account-id="999999999999"
これも出力が出ません。以下で確認します。
aws organizations list-delegated-administrators
出力が以下のようになればOKです。
{ "DelegatedAdministrators": [ { "Id": "999999999999", "Arn": "arn:aws:organizations::888888888888:account/o-xxxxxxxxxx/999999999999", "Email": "controltower@example.com", "Name": "Audit", "Status": "ACTIVE", "JoinedMethod": "CREATED", "JoinedTimestamp": "2020-04-27T12:43:08.952000+09:00", "DelegationEnabledDate": "2020-11-06T13:48:09.832000+09:00" } ] }
これで委任が完了しました。
続いて委任されたAuditアカウントでConformance Packsを展開していくのですが、その前に必要な情報を集めます。
展開するConformance PacksのサンプルテンプレートをGitHubから取得します。これはControl Towerではデフォルト無効化のガードレールも全て含まれていますので、Control Towerのガードレール一覧画面を見ながら必要に応じてコメントアウトしておきます。
先程作成されたConformance Packs用のS3バケットの名前を収集します。Log Archiveのアカウントのホームリージョンに展開されているスタックを確認しにいき、StackSet-CNFPACK-LOGARCHIVE-CUSTOM-CONFIG-STACKSET-******
というスタックの出力からバケット名を確認します。
以上を使ってConformance Packsの展開をしていきます。以下のコマンドを使い管理外リージョンにput-organization-conformance-pack
していきます。管理外リージョン11個分のコマンドをforで回しています。必要に応じアレンジしてください。--template-body
は適切なパスを指定し、--delivery-s3-bucket
は先程収集したバケット名を入れてください。
regions=("ap-northeast-1" "ap-northeast-2" "ap-south-1" "ap-southeast-1" "ca-central-1" "eu-central-1" "eu-north-1" "eu-west-2" "eu-west-3" "sa-east-1" "us-west-1") for r in $regions; do aws configservice put-organization-conformance-pack --organization-conformance-pack-name="CT-Conformance-Pack" --template-body="file://AWS-Control-Tower-Detective-Guardrails.yaml" --delivery-s3-bucket="awsconfigconforms-ffffffff" --region $r done
実行すると以下の出力が並びます。
{ "OrganizationConformancePackArn": "arn:aws:config:ap-northeast-1:999999999999:organization-conformance-pack/CT-Conformance-Pack-dpteiorv" }
適切に展開されたかは以下のget-organization-conformance-pack-detailed-status
コマンドで確認します。
aws configservice get-organization-conformance-pack-detailed-status --organization-conformance-pack-name CT-Conformance-Pack --region ap-northeast-1
出力された各アカウントが"Status": "CREATE_SUCCESSFUL"
となっていればOKです。
展開されたControl Tower管理外リージョンのデータがAuditのアグリゲーターに集まっていることを確認します。Auditアカウントでマネジメントコンソールにログインし、ホームリージョンのConfigから集約ビューのルールやリソースで各アカウントの状況を確認できます。非準拠の一覧はルールでコンプライアンス状況を非準拠
とすると表示可能です。
これでConformance Packsの展開は完了です。
Control Towerが新しいリージョンに対応した場合のアップグレード方法
Control Towerのアップデートが来て新しいリージョンに対応した場合には、そのリージョンのConfigとConformance Packsを一度外します。
まずConfigを外すためにマスターアカウントにログインしホームリージョンのStackSetsの画面を開きます。CUSTOM-CONFIG-STACKSET
のスタックセットの詳細から右上のアクションを押し「StackSetからスタックを削除」を押します。
展開済みのアカウントIDをカンマ区切りで入れるか、OUを指定して削除するリージョンのみを指定します。今回はap-northeast-1とします。次へ進んで実行します。
オペレーションが開始されるので、「スタックインスタンス」タブで該当リージョンをクエリしてしばらく待ちます。全て削除が完了するとなにも表示されなくなります。
続いて新しいアカウントが作成されたときに参照するパラメータストアから該当リージョンを削除します。マスターアカウントのCloudFormationスタック画面でExtendedRegionStack
の「出力」タブからパラメータストアのリンクを開きます。
右上の編集から編集して該当リージョンを削除します。今回はap-northeast-1,
を削除します。カンマを忘れずに。
そしてConformance Packsを削除します。これは委任されているAuditアカウントで以下のコマンドを実行します。
aws configservice delete-organization-conformance-pack --organization-conformance-pack-name "CT-Conformance-Pack" --region ap-northeast-1
確認は展開時と同様以下のコマンドで確認できます。
aws configservice get-organization-conformance-pack-detailed-status --organization-conformance-pack-name CT-Conformance-Pack --region ap-northeast-1
すべてなくなったらNoSuchOrganizationConformancePackException
のエラーとなりました。
完了したら該当リージョンからのConfigとConformance Packsを外せているので、Control Towerの更新手順に従い更新します。
展開した環境を元に戻す
検証用に実行したり、その他の都合でこの仕組みが要らなくなった場合は以下の手順で戻します。
まず展開した全てのリージョンのConformance Packsを削除します。Auditから以下を実行します。
regions=("ap-northeast-1" "ap-northeast-2" "ap-south-1" "ap-southeast-1" "ca-central-1" "eu-central-1" "eu-north-1" "eu-west-2" "eu-west-3" "sa-east-1" "us-west-1") for r in $regions; do aws configservice delete-organization-conformance-pack --organization-conformance-pack-name "CT-Conformance-Pack" --region $r done
委任を取り消します。マスターアカウントから以下のコマンドを実行します。
aws organizations deregister-delegated-administrator --account-id="999999999999" --service-principal=config-multiaccountsetup.amazonaws.com
実行したら以下で委任されたアカウントの有無を確認できます。
aws organizations list-delegated-administrators
空のリストが返ってこれば正常です。
Conformance Packsのマルチアカウント展開の機能を利用しない場合はこれも無効化します。
aws organizations disable-aws-service-access --service-principal=config-multiaccountsetup.amazonaws.com
これは以下で確認できます。config-multiaccountsetup.amazonaws.comが含まれていなければOKです。
aws organizations list-aws-service-access-for-organization
あとはCloudFormationで展開したものを消していきます。StackSetsの削除には中身のスタックインスタンスを全て削除してから行う必要があり、手順ではそれを手動で削除しに行くように書かれていますが、一番最初に展開したExtendedRegionStack
のLambdaがよくできていて、そのあたりをいい感じに削除してくれるため、StackSetsには触れずにExtendedRegionStack
を削除するだけで綺麗にできました。もしこれでうまく行かなかったら元の手順通りやってください。
スタックが消えたら、残っているLog ArchiveのS3バケットを削除します。これだけはスタック削除時に消えないのでマネジメントコンソールからアクセスして、バケットの中身を空にしてから削除します。
以上でクリーンアップ完了です。
まとめ
Control Towerの管理外リージョンに対してもガードレールを利かせる仕組みを作ってみました。AWS公式で出ているところが心強いですね。
どうしても現状のControl Towerでは全リージョンに対してガードレールを展開できないので渋っていることが多かったですが、これがあれば1つ懸念を払拭できますね!
ぜひこれを気にControl Towerを検討してみてはいかがでしょうか?